import { workspaceRoot } from '@nx/devkit';
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
import { defineConfig } from '@playwright/test';
import { lstatSync } from 'node:fs';
import { dirname, join, relative } from 'node:path';

export interface NxPlaywrightOptions {
  /**
   * The directory where the e2e tests are located.
   * @default './src'
   **/
  testDir?: string;

  /**
   * Whether to generate blob reports. Useful when running atomized tasks in CI
   * and you want to merge the reports.
   * @default `!!process.env['CI']`
   */
  generateBlobReports?: boolean;
}

/**
 * nx E2E Preset for Playwright
 * @description
 * this preset contains the base configuration
 * for your e2e tests that nx recommends.
 * By default html reporter is configured
 * along with the following browsers:
 * - chromium
 * - firefox
 * - webkit
 * These are generated by default.
 *
 * you can easily extend this within your playwright config via spreading the preset
 * @example
 * export default defineConfig({
 *   ...nxE2EPreset(__filename, options)
 *   // add your own config here
 * })
 *
 * @param pathToConfig will be used to construct the output paths for reporters and test results
 * @param options optional configuration options
 */
export function nxE2EPreset(
  pathToConfig: string,
  options?: NxPlaywrightOptions
) {
  const normalizedPath = lstatSync(pathToConfig).isDirectory()
    ? pathToConfig
    : dirname(pathToConfig);
  const projectPath = relative(workspaceRoot, normalizedPath);
  const offset = relative(normalizedPath, workspaceRoot);

  const isTsSolutionSetup = isUsingTsSolutionSetup();

  const testResultOuputDir = isTsSolutionSetup
    ? 'test-output/playwright/output'
    : join(offset, 'dist', '.playwright', projectPath, 'test-output');

  const reporters = [];
  reporters.push([
    'html',
    {
      outputFolder: isTsSolutionSetup
        ? 'test-output/playwright/report'
        : join(offset, 'dist', '.playwright', projectPath, 'playwright-report'),
    },
  ]);
  const shouldGenerateBlobReports =
    options?.generateBlobReports ?? !!process.env['CI'];
  if (shouldGenerateBlobReports) {
    reporters.push([
      'blob',
      {
        outputDir: isTsSolutionSetup
          ? 'test-output/playwright/blob-report'
          : join(offset, 'dist', '.playwright', projectPath, 'blob-report'),
      },
    ]);
  }

  return defineConfig({
    testDir: options?.testDir ?? './src',
    outputDir: testResultOuputDir,
    /* Run tests in files in parallel */
    fullyParallel: true,
    /* Fail the build on CI if you accidentally left test.only in the source code. */
    forbidOnly: !!process.env.CI,
    /* Retry on CI only */
    retries: process.env.CI ? 2 : 0,
    /* Opt out of parallel tests on CI. */
    workers: process.env.CI ? 1 : undefined,
    /* Reporter to use. See https://playwright.dev/docs/test-reporters */
    reporter: [...reporters],
  });
}
